﻿//-----------------------------------------------------------------------
// <copyright file="UnitOfWork.cs" company="WpfDevelopment.com">
//     Copyright WpfDevelopment.com. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Hrmsystem.Data
{
    using System;
    using System.Data.Entity;
    using System.Transactions;
    using WpfDevelopment.Data;
    using WpfDevelopment.MVVM;

    /// <summary>
    /// A unit of work used to store items with a (sort of) transaction to the persistant store
    /// </summary>
    public class UnitOfWork : IUnitOfWork
    {
        /// <summary>
        /// use a transaction when performing unit of work
        /// </summary>
        private bool useSqlTransaction = false;

        /// <summary>
        /// The transaction scope to use
        /// </summary>
        private TransactionScope transaction;

        /// <summary>
        /// Initializes a new instance of the <see cref="UnitOfWork"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        public UnitOfWork(DbContext context)
            : this(context, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UnitOfWork"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="useSqlTransaction">if set to <c>true</c> [use SQL transaction].</param>
        public UnitOfWork(DbContext context, bool useSqlTransaction)
        {
            this.Context = context;
            this.useSqlTransaction = useSqlTransaction;

            this.BeginTransaction();
        }

        /// <summary>
        /// Gets the context in which objects are persisted, should probaly not be used.
        /// </summary>
        /// <value>The context.</value>
        public object Context
        {
            get;
            private set;
        }

        /// <summary>
        /// Adds the specified entity.
        /// </summary>
        /// <typeparam name="T">The type of entity to add</typeparam>
        /// <param name="entity">The entity.</param>
        public void Add<T>(T entity) where T : ModelBase
        {
            ((DbContext)this.Context).Set<T>().Add(entity);
        }

        /// <summary>
        /// Updates the specified entity.
        /// </summary>
        /// <typeparam name="T">The type of entity to update</typeparam>
        /// <param name="entity">The entity.</param>
        public void Update<T>(T entity) where T : ModelBase
        {
            ((DbContext)this.Context).Set<T>().Attach(entity);
        }

        /// <summary>
        /// Deletes the specified entity.
        /// </summary>
        /// <typeparam name="T">The type of entity to delete</typeparam>
        /// <param name="entity">The entity.</param>
        public void Delete<T>(T entity) where T : ModelBase
        {
            ((DbContext)this.Context).Set<T>().Remove(entity);
        }

        /// <summary>
        /// Begins the transaction.
        /// </summary>
        public void BeginTransaction()
        {
            if (this.useSqlTransaction)
            {
                this.transaction = new TransactionScope();
            }
        }

        /// <summary>
        /// Commits the transaction.
        /// </summary>
        public void CommitTransaction()
        {
            try
            {
                if (this.useSqlTransaction && this.transaction == null)
                {
                    throw new TransactionException("The current transaction is not started!");
                }

                ((DbContext)this.Context).SaveChanges();

                if (this.useSqlTransaction)
                {
                    this.transaction.Complete();
                }
            }
            finally
            {
                if (this.useSqlTransaction)
                {
                    this.transaction.Dispose();
                }
            }
        }

        /// <summary>
        /// Rollbacks the transaction.
        /// </summary>
        public void RollbackTransaction()
        {
            if (this.useSqlTransaction && this.transaction != null)
            {
                this.transaction.Dispose();
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.useSqlTransaction && this.transaction != null)
                {
                    this.RollbackTransaction();
                }

                ((DbContext)this.Context).Dispose();
            }
        }
    }
}
